package cbbx_sm.decision_maker;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.util.Map.Entry;

import cbbx_sm.probabilistic_model.Cluster;
import cbbx_sm.probabilistic_model.Prediction;

/**
 * Very simple decision maker: it decides to probe the cluster with
 * the highest probability to contain an entity in the future state.
 * 
 * @author Alessio Della Motta - University of California, Irvine
 *
 */
public class SmartMostLikelyClusterDecisionMaker implements IDecisionMaker {
	private double alpha;
	private double beta;
	
	public SmartMostLikelyClusterDecisionMaker(double alpha, double beta){
		this.alpha = alpha;
		this.beta = beta;
	}
	
	@Override
	public Decision makeDecision(Prediction currentPrediction) {
		HashMap<Cluster, Double> probs = currentPrediction.getClusterProbabilities();
		HashMap<String, Double> cameraUpUtility = new HashMap<String, Double>();
		
		for (Entry<Cluster, Double> prob : probs.entrySet()) {
			String cameraId = prob.getKey().getCameraId();
			if (!cameraUpUtility.containsKey(cameraId)) {
				cameraUpUtility.put(prob.getKey().getCameraId(), prob.getValue() * beta);
			} else {
				cameraUpUtility.put(cameraId, 
					cameraUpUtility.get(cameraId) + prob.getValue() * beta);
			}
		}
		HashMap<String, Cluster> clustersToProbe = new HashMap<String, Cluster>();
		HashMap<String, Double> clustersToProbeProbs = new HashMap<String, Double>();
		
		for (Cluster cluster : probs.keySet()){
			String curCameraId = cluster.getCameraId();
			double curProb = probs.get(cluster);
			
			/*
			 * If the current cluster is the first cluster analyzed for a certain
			 * camera, then we insert it into the possible candidates; otherwise,
			 * if there's a cluster of the same camera as a candidate, we control
			 * if its probability is lower and, in that case, we substitute it
			 * with the current analyzed cluster.
			 */
			if (clustersToProbe.containsKey(curCameraId)){
				if(curProb > clustersToProbeProbs.get(curCameraId)){
					clustersToProbe.put(curCameraId, cluster);
					clustersToProbeProbs.put(curCameraId, curProb);
				}
			}
			else {
				// See if zooming in has a higher utility than zooming out.
				if ((alpha * curProb) > cameraUpUtility.get(curCameraId)){
					clustersToProbe.put(curCameraId, cluster);
					clustersToProbeProbs.put(curCameraId, curProb);
				}
			}
		}
		
		List<CameraConfiguration> confs = new Vector<CameraConfiguration>();
		
		for (Cluster cluster : clustersToProbe.values()) {
			confs.add(new CameraConfiguration(cluster.getCameraId(), cluster));
		}
		
		Decision decision = new Decision(confs);
		
		return decision;
	}
	
	@Override
	public String toString(){
		// LookAheadDecisionMakertrue_6_1.0_0.5_0.010000_30000.000000_1
		return String.format("%s_6_%f_%f_0_0_0", this.getClass().getSimpleName(), alpha, beta);
	}
}
